#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "customglwidget.h"

#include <QMessageBox>
#include <QGLWidget>
#include <QString>
#include <QDir>

// variables mainly controlling drawing
const int windowSize = 500; // max size of bar graphs
int yH = 55; // upper y
int yL = 555; // lower y
int xL = 100; // left x
int xR = 350; // right x
int ll = 0; // used for insensity of left bar red colour
int rr = 0; // used for insensity of right bar red colour
int lefty = 250; //Nm measurements from devices
int righty = 250;
int leftOffset = 250; // ratio of slider and Nm values
int rightOffset = 250;
int lefttrue = lefty * leftOffset; // drawing, length of bars
int righttrue = righty * rightOffset;
int strings = 0;
bool status = false; // if device is connected
bool made = false; // if control panel is made
bool savehigh = true;
QString displayString = "Device not loaded";
QString fileelements[5] = {""};



/**********************
 * Constructor
 */
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    //intialise NGIO device, and try load device
    ngios = new Ngio();
    ngios->FirstStep();
    status = ngios->getStatus(); // loaded successfully?

    ui->setupUi(this);
    setWindowTitle("Bubble Blaster");

    //initate timer that controls readings update, and painting
    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(updateSlot()));
    timer->start(20);


    // Set scene and graphics view
    scene = new CScene();
    view = new QGraphicsView(this);
    view->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
    view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
    view->setScene(scene);
    setCentralWidget(view);
    ui->actionStart->setEnabled(true);
    ui->actionPause->setEnabled(false);
    ui->actionStop->setEnabled(false);
    ui->action1_Player->setEnabled(false);
    ui->action1_Player->setChecked(true);

    // connect the signals and slots
    connect(this, SIGNAL(sentButton(int)), scene, SLOT(whatsaHappenin(int)));
    connect(this, SIGNAL(setPlayers(bool)), scene, SLOT(setPlayer(bool)));
    connect(scene, SIGNAL(gameOver()), this, SLOT(gameOverFix()));
    connect(scene, SIGNAL(newScore(int, int)), this, SLOT(highScoreChange(int,int)));

    currentuser = new user(); // make a default user

    if( !QDir("profiles").exists()) QDir().mkdir("profiles"); //make a 'profiles' folder
    profilespath = QCoreApplication::applicationDirPath();
    profilespath.append("/profiles/");

    // check for dynamometer connectivity
    if(!status)
        errorOut("Dynamometers did not load properly.\nPlease reconnect them, and then\nreload them from 'Options' menu.");

}


/**********************
 * Destructor
 */
MainWindow::~MainWindow()
{
    ngios->ThirdStep(); //destroy device reader properly
    timer->stop();
    delete view;
    delete scene;
    delete ui;
}


/**********************
 * Creates new 'Controls' window when menu item is triggered
 */
void MainWindow::on_actionNew_Window_triggered()
{

    mDialog = new MyDialog(this, currentuser);

    made = true;

    connect(mDialog, SIGNAL(showScore(bool)), scene, SLOT(showScore(bool)));
    connect(mDialog, SIGNAL(setGameTime(int)), scene, SLOT(gameTime(int)));
    connect(mDialog, SIGNAL(buttonPushed(int)), this, SLOT(fromDialog(int)));
    connect(this, SIGNAL(feedback(int)), mDialog, SLOT(fromTheOtherSide(int)));
    connect(this, SIGNAL(score(int,int)), mDialog, SLOT(scoreChange(int,int)));
    connect(mDialog, SIGNAL(dyingCall()), this, SLOT(iAmDying()));
    connect(this, SIGNAL(setPlayers(bool)), mDialog, SLOT(isOnePlayer(bool)));

    ui->actionNew_Window->setEnabled(false);

    QTimer::singleShot(400, this, SLOT(update())); // let things settle

    mDialog->show();

}


/**********************
 * Sets the high score and sends it to the control box, and sends normal score to
 * control box too. If 2 player, sends both over.
 */
void MainWindow::highScoreChange(int high, int newone){
    if(high == 1 && savehigh == true) currentuser->setHigh(newone); // if new high score, save
    if(made) emit score(high, newone);
}


/**********************
 * Slot for when timer fires, getting readings from dynamometers, and
 * the control window, and repaints the charts
 */
void MainWindow::updateSlot()
{
    // perform measurement
    ngios->SecondStep();
    lefty = ngios->getLeft();
    righty = ngios->getRight();

    //get slider info and work out Nm/slider ratio
    leftOffset = windowSize/mDialog->getLeft();
    rightOffset = windowSize/mDialog->getRight();

    //work out graphing measurements
    lefttrue = lefty * (leftOffset > 0 ? leftOffset : 0);
    righttrue = righty * (rightOffset > 0 ? rightOffset: 0);
    scene->ChangeChildValues(((double)lefttrue/windowSize)*100, ((double)righttrue/windowSize)*100);
}


/**********************
 * Slot for 'Close' menu item that closes the program when it is pressed
 */
void MainWindow::on_actionClose_triggered()
{
    MainWindow::close();
}


/**********************
 * Slot for 'Reload device' that reloads the device if it has not successfully loaded.
 */
void MainWindow::on_actionReload_Device_triggered()
{
    if(status == false)
    { // reload device
        ngios = new Ngio();
        ngios->FirstStep();
        status = ngios->getStatus();
    }
    else
    {
        // if device is already loaded, do not reload but display alert
        errorOut("Device is already loaded");
    }
}


/**********************
 * Start button
 */
void MainWindow::on_actionStart_triggered()
{
    emit sentButton(1);
    if(made) emit feedback(1);
    ui->actionStart->setEnabled(false);
    ui->actionPause->setEnabled(true);
    ui->actionStop->setEnabled(true);
    ui->actionNew_Window->setEnabled(false);
    ui->menuPlayers_2->setEnabled(false);
    ui->menuLoad_Save_profile->setEnabled(false);
    if(ui->action1_Player->isEnabled() == false) savehigh = true;
}


/**********************
 * Pause button
 */
void MainWindow::on_actionPause_triggered()
{
    emit sentButton(2);
    if(made) emit feedback(2);
    ui->actionStart->setEnabled(true);
    ui->actionPause->setEnabled(false);
}


/**********************
 * Stop button
 */
void MainWindow::on_actionStop_triggered()
{
    emit sentButton(0);
    if(made) emit feedback(0);
    ui->actionStart->setEnabled(true);
    ui->actionPause->setEnabled(false);
    ui->actionStop->setEnabled(false);
    ui->actionNew_Window->setEnabled(true);
    ui->menuPlayers_2->setEnabled(true);
    ui->menuLoad_Save_profile->setEnabled(true);
}


/**********************
 * Slot that adjusts buttons at game-over time
 */
void MainWindow::gameOverFix(){
    if(made) emit feedback(3);
    ui->actionStart->setEnabled(true);
    ui->actionPause->setEnabled(false);
    ui->actionStop->setEnabled(false);
    ui->menuPlayers_2->setEnabled(true);
    ui->menuLoad_Save_profile->setEnabled(true);
}


/**********************
 * Slot for receiving button commands from controller window
 */
void MainWindow::fromDialog(int x){
    made = false;
    if(x == 0) on_actionStop_triggered();
    if(x == 1) on_actionStart_triggered();
    if(x == 2) on_actionPause_triggered();
    made = true;
}


/**********************
 * Singleton class cleanup - from controller box closing
 */
void MainWindow::iAmDying(){
    made = false;
    ui->actionNew_Window->setEnabled(true);
}


/**********************
 * Load profile button
 */
void MainWindow::on_actionLoad_settings_triggered()
{
    loadfile = QFileDialog::getOpenFileName(this, tr("Open Profile"), profilespath, tr("TXT files (*.TXT)"));
    if(loadfile != NULL){
        readIn();
    }
}


/**********************
 * Save profile button
 */
void MainWindow::on_actionSave_settings_triggered()
{
    if(loadfile == NULL) saveFileAs();
    else saveFile(loadfile);
}


/**********************
 * Generic alert box, you call it and send it a message
 */
void MainWindow::errorOut(QString message){
    QMessageBox msgBox;
    msgBox.setWindowTitle("ALERT");
    msgBox.setIcon(QMessageBox::NoIcon);
    msgBox.setText(message);
    msgBox.exec();
}


/**********************
 * Saves current user levels/options.
 */
void MainWindow::saveFile(QString name) //save the existing file
{
    QFile file(name);
    if (file.open(QIODevice::WriteOnly|QIODevice::Text))
    {
        QTextStream out(&file);
        out << "HIGHSCORE: " << currentuser->getHigh() << "\n";
        out << "LEFTLEVEL: " << currentuser->getLeft() << "\n";
        out << "RIGHTLEVEL: " << currentuser->getRight() << "\n";
        out << "GAMETIME: " << currentuser->getGame() << "\n";
        out << "SHOWSCORES: " << (currentuser->getShore() == true ? 1 : 0) << "\n";
        file.close();

        int index = name.lastIndexOf("/");
        QString names = name.remove(0, index + 1);
        names.chop(4);
        currentuser->setName(names);
        setWindowTitle(currentuser->getName());
    }
}


/**********************
 * Save As stuff
 */
void MainWindow::saveFileAs() //save as a new file
{
    mloadfile = QFileDialog::getSaveFileName(this, tr("New Profile"), profilespath, tr("TXT files (*.TXT)"));
    if(mloadfile.isEmpty())
        return;
    saveFile(mloadfile);
}


/**********************
 * Reads in profile file lines
 */
void MainWindow::readIn(){
    QFile filetoload(loadfile);
    if (!filetoload.open(QIODevice::ReadWrite | QIODevice::Text))
    {
        errorOut("File did not load");
    } else {
        QTextStream in(&filetoload);
        while (!in.atEnd()) {
            fileelements[strings++] = in.readLine();
        }
        if(strings == 5){
            processLines();
        } else {
            errorOut("Files is corrupted");
        }
        filetoload.close();
    }
    strings = 0;
}


/**********************
 * Adds profile settings to current program user
 */
void MainWindow::processLines(){
    for(int i = 0; i < 5; i ++){
        int index = fileelements[i].indexOf(":");
        fileelements[i].remove(0,index + 2);
    }
    int index = loadfile.lastIndexOf("/");
    QString names = loadfile.remove(0, index + 1);
    names.chop(4);

    currentuser = new user(names, fileelements[0].toInt(0, 10), fileelements[1].toInt(0, 10), fileelements[2].toInt(0, 10), fileelements[3].toInt(0, 10), (fileelements[4] == "0" ? false : true));
    if(currentuser != NULL) loadUser();
    else errorOut("Couldn't load profile");
}


/**********************
 * Loads profile settings
 */
void MainWindow::loadUser(){
    setWindowTitle(currentuser->getName());
    scene->showScore(currentuser->getShore());
    scene->setHigh(currentuser->getHigh());
    scene->gameTime(currentuser->getGame());

    if(made == true){
        mDialog->~MyDialog();
        on_actionNew_Window_triggered();
    } else {
        leftOffset = windowSize/currentuser->getLeft();
        rightOffset = windowSize/currentuser->getRight();
    }
}


/**********************
 * Save profile button
 */
void MainWindow::on_actionSave_new_user_triggered()
{
    saveFileAs();
}


/**********************
 * One player selected
 */
void MainWindow::on_action1_Player_triggered()
{
    ui->action1_Player->setEnabled(false);
    ui->action1_Player->setChecked(true);
    ui->action2_Players_2->setEnabled(true);
    ui->action2_Players_2->setChecked(false);
    emit setPlayers(true);
}


/**********************
 * Two player selected
 */
void MainWindow::on_action2_Players_2_triggered()
{
    ui->action1_Player->setEnabled(true);
    ui->action1_Player->setChecked(false);
    ui->action2_Players_2->setEnabled(false);
    ui->action2_Players_2->setChecked(true);
    emit setPlayers(false);
    savehigh = false;
}


/**********************
 * Help button selected
 */
void MainWindow::on_actionHelp_triggered()
{
    QTextBrowser *help=new QTextBrowser(this);
    help->setWindowFlags(Qt::Window); //or Qt::Tool, Qt::Dialog if you like
    help->setReadOnly(true);

    QFile file("include/help.txt");
    QTextStream stream ( &file );

    if (!file.open (QIODevice::ReadOnly))
    {
        errorOut("Help file could not be found");
    } else {
        help->setHtml(stream.readAll());
        file.close(); // when your done.
        help->setWindowTitle("Help");
        help->setMinimumWidth(400);
        help->setMinimumHeight(400);
        help->show();
    }
}
